{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "<font color=\"#a9a56c\" size=2> **@Author: Arif Kasim Rozani - (Team Operation Badar)** </font>"
      ],
      "metadata": {
        "id": "38_QpUXJOAII"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# **Working with Lists and Tuples**\n",
        "\n",
        "## **Introduction**\n",
        "\n",
        "Python provides powerful sequence types: `lists and tuples`. These data structures help store and manage collections of data efficiently."
      ],
      "metadata": {
        "id": "Q7_0iqS1mH1h"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **1. Lists in Python**\n",
        "\n",
        "1. **Ordered**: Lists are `ordered`, meaning that the items in the list have a specific order and can be accessed by their index.\n",
        "2. **Mutable**: Lists are `mutable`, meaning that they can be modified after they are created.\n",
        "3. **Indexed**: Lists are `indexed`, meaning that each item in the list has a specific index that can be used to access it.\n",
        "4. **Dynamic size**: Lists can `grow or shrink` dynamically as elements are added or removed.\n",
        "5. **Heterogeneous**: Lists can contain elements of `different data types`, such as integers, strings, floats, and other lists.\n",
        "6. **Supports duplicate values**: Lists can contain `duplicate values`.\n",
        "\n",
        "<br>\n",
        "\n",
        "\n",
        "Creating a List"
      ],
      "metadata": {
        "id": "lb7TDimCmXuP"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Creating lists with different data types\n",
        "fruits: list  = [\"apple\", \"banana\", \"cherry\"]\n",
        "numbers: list = [10, 20, 30, 40]\n",
        "mixed: list   = [\"hello\", 42, 3.14, True]\n",
        "\n",
        "print(\"fruits  = \", fruits)\n",
        "print(\"numbers = \", numbers)\n",
        "print(\"mixed   = \", mixed)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5RVnXKqpma3g",
        "outputId": "0036d1c6-423c-492a-f7e3-e33d8255fffd"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "fruits  =  ['apple', 'banana', 'cherry']\n",
            "numbers =  [10, 20, 30, 40]\n",
            "mixed   =  ['hello', 42, 3.14, True]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Accessing List Elements**\n",
        "\n",
        "You can access elements using indexing (**starting from 0**) and negative indexing (**starting from -1**)."
      ],
      "metadata": {
        "id": "jkrjnRFcm9KZ"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "fruits: list = [\"apple\", \"banana\", \"cherry\"]\n",
        "print(fruits[0])   # Output: apple\n",
        "print(fruits[-3])  # Output: apple, accessing element in reverse order"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "P_jrJ9zinAqY",
        "outputId": "91e6bb81-6506-465c-bf31-01eb9c014b93"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "apple\n",
            "apple\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Modifying Lists**\n",
        "\n",
        "Lists are mutable, meaning their elements can be changed."
      ],
      "metadata": {
        "id": "VneuC1AunsZu"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "fruits: list = [\"apple\", \"banana\", \"cherry\"]\n",
        "fruits[-3] = \"watermelon\" # replacing \"apple\" with \"watermelon\"\n",
        "print(fruits)  # Output: ['watermelon', 'banana', 'cherry']"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "14r6RohQnr83",
        "outputId": "1bb779e8-d33c-413c-da1d-c49154cc60b7"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['watermelon', 'banana', 'cherry']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **List Slicing**\n",
        "\n",
        "Extract multiple elements using slicing."
      ],
      "metadata": {
        "id": "8tFXd6XuoUe2"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "print(fruits[0:2])  # Output: ['watermelon', 'banana'] 0 and 1"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "kGEM8JWdodI1",
        "outputId": "4303cd1b-a96e-4d46-e030-22b93a85aa1f"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['watermelon', 'banana']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **2. Common List Methods**\n",
        "\n",
        "Lists provide built-in methods for efficient data manipulation.\n",
        "\n",
        "Appending and Extending Lists"
      ],
      "metadata": {
        "id": "dpUTFlblozsu"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "fruits.append(\"mango\")  # Adds a single element 'mango' to the end\n",
        "print(fruits)  # Output: ['watermelon', 'banana', 'cherry', 'mango']"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_aX2jplDpCae",
        "outputId": "bf1f91da-0636-428c-cb00-0bcd8e58761a"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['watermelon', 'banana', 'cherry', 'mango']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "fruits.extend([\"grape\", \"kiwi\"])  # Adds multiple elements\n",
        "print(fruits)  # Output: ['watermelon', 'banana', 'cherry', 'mango', 'grape', 'kiwi']"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "paNiwmTUpunk",
        "outputId": "cb756d51-839f-498e-81fd-a9ddc3c33701"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['watermelon', 'banana', 'cherry', 'mango', 'grape', 'kiwi']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Removing Elements**\n",
        "\n",
        "In Python, `remove()` and `pop()` are two distinct methods used to manipulate lists. While they may seem similar, they have different purposes and behaviors.\n",
        "\n",
        "**Remove() Method**\n",
        "\n",
        "The `remove()` method is used to delete the first occurrence of a specified value from a list. If the value is not found in the list, a `ValueError` exception is raised.\n",
        "\n",
        "**Key aspects of remove():**\n",
        "\n",
        "1. **Value-based**: `remove()` searches for a specific value in the list.\n",
        "\n",
        "2. **Returns None**: The `remove()` method does not return any value.\n",
        "3. **Raises ValueError**: If the value is not found in the list, a `ValueError` exception is raised."
      ],
      "metadata": {
        "id": "PRnEMK7hpmel"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "fruits.remove(\"banana\")  # Removes 'banana' # run multiple times to see error as \"banana\" is already removed\n",
        "print(fruits)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "LETzO4OA3-BY",
        "outputId": "757e55b0-ec09-4370-e2dc-05b68c7fdfc2"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['watermelon', 'cherry', 'mango', 'grape', 'kiwi']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Pop() Method**\n",
        "\n",
        "The `pop()` method is used to delete an item at a specified index from a list. If no index is provided, it removes and returns the last item in the list.\n",
        "\n",
        "**Key aspects of pop():**\n",
        "\n",
        "1. **Index-based**: `pop()` searches for an item at a specific index in the list.\n",
        "\n",
        "2. **Returns the removed item**: The `pop()` method returns the item that was removed from the list.\n",
        "3. **Raises IndexError**: If the index is out of range, an `IndexError` exception is raised."
      ],
      "metadata": {
        "id": "tjtVBpfm1O0B"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "deleted = fruits.pop(1)  # Removes and returns the element at index 1 # run it multiple time to see error\n",
        "print(\"deleted element = \", deleted)  # Output: 'cherry'\n",
        "print(fruits) # Output: ['watermelon', 'mango', 'grape', 'kiwi']"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Fz_ERu854wPq",
        "outputId": "a29f7ab3-70d1-4a8d-8164-7c4d0cb9a0b0"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "deleted element =  cherry\n",
            "['watermelon', 'mango', 'grape', 'kiwi']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Sorting a List**"
      ],
      "metadata": {
        "id": "bkfmMy3k475R"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **1. Default Sorting (Ascending Order)**"
      ],
      "metadata": {
        "id": "M5V2V4yaTB0j"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "numbers: list[int] = [3, 1, 4, 1, 5, 9] # unsorted list\n",
        "numbers.sort()\n",
        "print(numbers)  # Output: [1, 1, 3, 4, 5, 9]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "NNxZuC2F499f",
        "outputId": "ac73973f-1e3e-4095-9f9a-3d11f96b62e9"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[1, 1, 3, 4, 5, 9]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **2. Sorting in Descending Order (reverse=True)**\n",
        "\n",
        "*(Contributor: Amna Aftab Kifayat from Karachi)*"
      ],
      "metadata": {
        "id": "A8s5KWX2S6VM"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "numbers = [4, 2, 9, 1]\n",
        "numbers.sort(reverse=True)\n",
        "print(numbers)  # Output: [9, 4, 2, 1]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "knnXQekGTF6T",
        "outputId": "83cf74e5-c38d-41b7-cd49-ed8702321f07"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[9, 4, 2, 1]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **3. Sorting by String Length (key=len)**"
      ],
      "metadata": {
        "id": "5r-Jg2h1T_XT"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "words = [\"apple\", \"kiwi\", \"banana\"]\n",
        "words.sort(key=len)\n",
        "print(words)  # Output: ['kiwi', 'apple', 'banana']"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jGBU6vTbUBvz",
        "outputId": "91cf822c-965d-44c7-83b4-d615bcb40fa5"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['kiwi', 'apple', 'banana']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **4. Sorting by Last Character (key=lambda word: word[-1])**"
      ],
      "metadata": {
        "id": "WW8dD1dvUHRS"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "words = [\"apple\", \"kiwi\", \"banana\"]\n",
        "words.sort(key=lambda word: word[-1])\n",
        "print(words)  # Output: ['banana', 'apple', 'kiwi']  # Sorted by last letter"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "qYx1yiOsUJrD",
        "outputId": "1ac108cd-0960-444d-944e-25cc0a4429ee"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "['banana', 'apple', 'kiwi']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **5. Reverse Sorting**"
      ],
      "metadata": {
        "id": "l_a5FaZrUf8b"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "numbers = [1, 2, 5, 7, 10]\n",
        "numbers.reverse()\n",
        "print(numbers)  # Output: [10, 7, 5, 2, 1]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "i04BleqO5ING",
        "outputId": "bac746c3-bcaf-4d88-9a7e-fb8362915eba"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[10, 7, 5, 2, 1]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **3. Iterating Over Lists**\n",
        "\n",
        "Use loops to process elements in a list.\n",
        "\n",
        "\n",
        "**Using a for-loop**"
      ],
      "metadata": {
        "id": "i-hqSKvf5QM2"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "for fruit in fruits:\n",
        "    print(fruit)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "81InAzgV5lZG",
        "outputId": "89a917ab-8610-4ae7-9411-7c02efec8e03"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "watermelon\n",
            "mango\n",
            "grape\n",
            "kiwi\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Custome Iterator: Agentic AI - Python - Lesson 13 - OOP: Objects & Classes - Part 2**\n",
        "\n",
        "[How to Make a Custom Class Iterable](https://colab.research.google.com/drive/13i4LN9HrdFbp_GK-IEoKU8OCZh6F4Ilp?usp=sharing#scrollTo=AJrmBy8pgzSO)"
      ],
      "metadata": {
        "id": "0aPKIMKVjeXn"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# **Using list comprehension**\n",
        "\n",
        "List comprehension is a powerful feature in Python that allows you to create new lists in a `concise` and `readable way`. It's a `compact way` to create lists from existing lists or other iterables by applying a transformation or filter to each element.\n",
        "\n",
        "```python\n",
        "new_list = [expression for element in iterable if condition]\n",
        "```\n",
        "\n",
        "* `expression` is the operation you want to perform on each element.\n",
        "* `element` is the variable that takes on the value of each element in the `iterable`.\n",
        "* `iterable` is the list or other iterable that you want to process.\n",
        "* `condition` is an optional filter that determines whether an element is included in the new list.\n"
      ],
      "metadata": {
        "id": "suYxDGRO6BY-"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Without if condition\n",
        "squared: list = [x**2 for x in [1, 2, 3, 4, 5] ] #  if x > 3 place this if condition and see\n",
        "print(squared, \" : \", type(squared))  # Output: [1, 4, 9, 16, 25]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "FtSkvSQq6Ap_",
        "outputId": "8e96b2d3-81a1-4356-cad6-db782f51f8b3"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[1, 4, 9, 16, 25]  :  <class 'list'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# With if condition\n",
        "squared: list = [x**2 for x in [1, 2, 3, 4, 5] if x > 3] #  if x > 3 place this if condition and see\n",
        "print(squared, \" : \", type(squared))  # Output: [1, 4, 9, 16, 25]"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ruAekaxltyUJ",
        "outputId": "fbda0b22-7327-4cdb-a261-5fedd60c02ca"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[16, 25]  :  <class 'list'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**List comprehension is commonly used for:**\n",
        "\n",
        "* **`Transforming data`**: List comprehension can be used to transform data from one format to another.\n",
        "* **`Filtering data`**: List comprehension can be used to filter out unwanted data.\n",
        "* **`Creating new data`**: List comprehension can be used to create new data by combining existing data."
      ],
      "metadata": {
        "id": "PTlCR1KR64Vd"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "[w3schools: List Methods](https://www.w3schools.com/python/python_lists_methods.asp)"
      ],
      "metadata": {
        "id": "4K1718jQDNwX"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# **4. Tuples in Python**\n",
        "\n",
        "A tuple is an `ordered`, `immutable` (unchangeable) sequence of elements. Tuples are useful for fixed data collections.\n",
        "\n",
        "In Python, a tuple is an immutable data type. This means that once a tuple is created, its elements cannot be changed, added, or removed.\n",
        "\n",
        "### **1.  Cannot Modify Elements:**\n",
        "  * Once a tuple is created, you cannot change its elements.\n",
        "\n",
        "### **2. Cannot Add or Remove Elements:**\n",
        "  * You cannot add new elements to a tuple or remove existing ones.\n",
        "\n",
        "\n",
        "\n",
        "---\n",
        "\n",
        "\n",
        "\n",
        "## **Why Use Tuples?**\n",
        "\n",
        "  1.  **Immutable**: Since tuples cannot be changed, they are safer to use when you want to ensure that the data remains constant.\n",
        "\n",
        "  2.  **Hashable**: Tuples can be used as keys in dictionaries because they are immutable.\n",
        "  3.  **Performance**: Tuples are generally faster than lists because of their immutability.\n",
        "\n",
        "## **When to Use Tuples vs Lists**\n",
        "\n",
        "* Use tuples when you want to store data that should not change (e.g., coordinates, constants).\n",
        "\n",
        "* Use lists when you need a collection that can be modified (e.g., adding or removing elements).\n",
        "\n",
        "Creating a Tuple"
      ],
      "metadata": {
        "id": "iuNg44PM8PPs"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "tuple1: tuple = tuple([\"apple\", \"banana\", \"cherry\"]) # cast a list into tuple\n",
        "tuple2: tuple = (10, 20, 30) # tuple\n",
        "mixed_tuple: tuple = (\"hello\", 42, 3.14, True) # tuple\n",
        "\n",
        "print(\"tuple1      =\", tuple1)\n",
        "print(\"tuple2      =\", tuple2)\n",
        "print(\"mixed_tuple =\", mixed_tuple)"
      ],
      "metadata": {
        "id": "EFLG4Fv28VZD",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "4a161dbe-57e6-4b5a-8699-6d0cc8f9ede4"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "tuple1      = ('apple', 'banana', 'cherry')\n",
            "tuple2      = (10, 20, 30)\n",
            "mixed_tuple = ('hello', 42, 3.14, True)\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Even though tuples are immutable, Python may create new instances in memory when you define identical tuples in separate assignments. This is why id(tuple_1) and id(tuple_2) may differ."
      ],
      "metadata": {
        "id": "UDNPJLRKwJgP"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "tuple_1: tuple = (10, 20, 30) # tuple\n",
        "tuple_2: tuple = (10, 20, 30) # tuple\n",
        "\n",
        "print(\"id(tuple_1) = \", id(tuple_1)) # unique memory address\n",
        "print(\"id(tuple_2) = \", id(tuple_2)) # unique memory address\n",
        "\n",
        "print(\"tuple_1 == tuple_2 = \", tuple_1 == tuple_2) # comparing by value"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "q8uWHcPIuu-Z",
        "outputId": "8804e8e5-f29f-48bd-e6cf-06e06fa3a307"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "id(tuple_1) =  139975700916672\n",
            "id(tuple_2) =  139975700971648\n",
            "tuple_1 == tuple_2 =  True\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "**Why are Tuples Immutable?**\n",
        "\n",
        "There are several reasons why tuples are immutable:\n",
        "\n",
        "1. **`Memory Efficiency`**: Immutable tuples can be stored in a single block of memory, which makes them more memory-efficient than lists.\n",
        "2. **`Thread Safety`**: Immutable tuples are thread-safe, meaning that they can be safely accessed and shared between multiple threads without fear of modification.\n",
        "3. **`Hashability`**: Immutable tuples are hashable, meaning that they can be used as keys in dictionaries.\n"
      ],
      "metadata": {
        "id": "iyY91pyS-Bob"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "*lets create an error.*"
      ],
      "metadata": {
        "id": "SNg90oga-y1a"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "tuple1[0] = \"watermelon\" # immutable"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 141
        },
        "id": "0BMQ9nbT94Vl",
        "outputId": "8290ef99-9652-4553-f38a-0929587647cc"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "error",
          "ename": "TypeError",
          "evalue": "'tuple' object does not support item assignment",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-31-e330c10a0867>\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mtuple1\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"watermelon\"\u001b[0m \u001b[0;31m# immutable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Tuples in Python\n",
        "\n",
        "# A tuple is an `ordered`, `immutable` (unchangeable) sequence of elements.\n",
        "# Tuples are useful for fixed data collections.\n",
        "\n",
        "# Creating a Tuple\n",
        "tuple1: tuple      = tuple([\"apple\", \"banana\", \"cherry\"])  # cast a list into tuple\n",
        "tuple2: tuple      = (10, 20, 30)  # tuple\n",
        "mixed_tuple: tuple = (\"hello\", 42, 3.14, True)  # tuple\n",
        "\n",
        "print(\"tuple1      =\", tuple1)\n",
        "print(\"tuple2      =\", tuple2)\n",
        "print(\"mixed_tuple =\", mixed_tuple)\n",
        "\n",
        "# Accessing elements in a tuple\n",
        "print(\"tuple1[0] =\", tuple1[0])  # Accessing first element\n",
        "\n",
        "# Tuple slicing\n",
        "print(\"tuple2[1:] =\", tuple2[1:])  # Slicing from index 1\n",
        "\n",
        "# Tuple length\n",
        "print(\"Length of tuple1:\", len(tuple1))\n",
        "\n",
        "# Iterating through a tuple\n",
        "print(\"Iterating through tuple2:\")\n",
        "for item in tuple2:\n",
        "  print(item)\n",
        "\n",
        "# Checking if an item exists in a tuple\n",
        "print(\"Is 20 in tuple2?\", 20 in tuple2)\n",
        "\n",
        "# Concatenating tuples\n",
        "tuple3: tuple = tuple1 + tuple2\n",
        "print(\"tuple1 + tuple2 =\", tuple3)\n",
        "\n",
        "# Repeating tuples\n",
        "tuple4: tuple = tuple2 * 2\n",
        "print(\"tuple2 * 2 =\", tuple4)\n",
        "\n",
        "# Nested tuples\n",
        "nested_tuple = (tuple1, tuple2)\n",
        "print(\"nested_tuple =\", nested_tuple)\n",
        "\n",
        "# Unpacking tuples\n",
        "a, b, c = tuple1\n",
        "print(\"Unpacking tuple1:\", a, b, c)\n",
        "\n",
        "# Using tuples as keys in dictionaries (because they are immutable)\n",
        "my_dict = {tuple1: \"This is a tuple key\", tuple2: \"Another tuple key\"}\n",
        "print(\"Dictionary with tuple keys:\", my_dict)\n",
        "\n",
        "#Trying to modify a tuple will result in a TypeError\n",
        "# tuple1[0] = \"watermelon\" #immutable. This line will raise an error. Uncomment to test."
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "braKUP09_sMC",
        "outputId": "841dca64-aebc-4421-e783-a8a2fea75547"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "tuple1      = ('apple', 'banana', 'cherry')\n",
            "tuple2      = (10, 20, 30)\n",
            "mixed_tuple = ('hello', 42, 3.14, True)\n",
            "tuple1[0] = apple\n",
            "tuple2[1:] = (20, 30)\n",
            "Length of tuple1: 3\n",
            "Iterating through tuple2:\n",
            "10\n",
            "20\n",
            "30\n",
            "Is 20 in tuple2? True\n",
            "tuple1 + tuple2 = ('apple', 'banana', 'cherry', 10, 20, 30)\n",
            "tuple2 * 2 = (10, 20, 30, 10, 20, 30)\n",
            "nested_tuple = (('apple', 'banana', 'cherry'), (10, 20, 30))\n",
            "Unpacking tuple1: apple banana cherry\n",
            "Dictionary with tuple keys: {('apple', 'banana', 'cherry'): 'This is a tuple key', (10, 20, 30): 'Another tuple key'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(tuple1[0])   # Output: apple\n",
        "print(tuple1[-3])  # Output: apple\n",
        "print(tuple1.count(\"apple\"))\n",
        "print(tuple1.index(\"apple\"))\n",
        "\n",
        "#error\n",
        "#tuple1.sort()\n",
        "#tuple1.reverse()\n",
        "#tuple1.append(\"mango\")\n",
        "#tuple1.extend([\"grape\", \"kiwi\"])\n",
        "#tuple1.remove(\"banana\")\n",
        "#deleted = tuple1.pop(1)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "TbOPMtv38mPE",
        "outputId": "70ddc7e2-ff44-4efa-b725-89e85414399a"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "apple\n",
            "apple\n",
            "1\n",
            "0\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: print the complete list of methods and attribute of tuple, dont include dunders\n",
        "\n",
        "# Get a list of all attributes and methods of a tuple\n",
        "tuple_methods: list = [method for method in dir(tuple) if not method.startswith('__')]\n",
        "\n",
        "# Print the list of methods (excluding dunder methods)\n",
        "tuple_methods\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "JaShEPLDBY0_",
        "outputId": "7234d667-d7b9-496b-8f18-7621e4031591"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "['count', 'index']"
            ]
          },
          "metadata": {},
          "execution_count": 53
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: generate a example of ['count', 'index'] in tuple\n",
        "\n",
        "tuple1: tuple = tuple([\"apple\", \"banana\", \"cherry\"])\n",
        "print(tuple1.count(\"apple\"))  # Output: 1\n",
        "print(tuple1.index(\"apple\"))  # Output: 0\n",
        "example_tuple: tuple = ('count', 'index')\n",
        "print(example_tuple) # Output: ('count', 'index')\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "oWs7jKPGBzEA",
        "outputId": "02447f9f-8bf1-483b-ac74-5cc1546375de"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1\n",
            "0\n",
            "('count', 'index')\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "[w3schools: Tuples](https://www.w3schools.com/python/python_tuples.asp)"
      ],
      "metadata": {
        "id": "D-qq7kCsEA5P"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Python is Type Hint Language**"
      ],
      "metadata": {
        "id": "nbPw5rKiCtYm"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "a: int = input (\"Enter your name: \")\n",
        "print(a, type(a) )"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UK-tDMVDFVes",
        "outputId": "52f469ff-63f9-43e0-e492-fa6303e112e3"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Enter your name: Arif Rozani\n",
            "Arif Rozani <class 'str'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Type Hinting (a: int)**\n",
        "* a: int is a type hint, which suggests that the variable a is expected to be an integer.\n",
        "* `However, type hints are not enforced in Python`. They are only for documentation and tools like linters or type checkers.\n",
        "* The actual value assigned to a will still be a string, because input() always returns a string."
      ],
      "metadata": {
        "id": "Y4W_vkU1JOAe"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "# **Dictionaries in Python**\n",
        "\n",
        "## **1. Introduction to Dictionaries**\n",
        "\n",
        "A dictionary is a collection of `key-value pairs`. It is:\n",
        "\n",
        "\n",
        "- **Ordered (since Python 3.7)**: Items are stored in the order they were inserted.\n",
        "\n",
        "- **Mutable**: Items can be added, removed, or modified after the dictionary is created.\n",
        "- **Un-indexed**: Items are accessed using keys, not indices.\n",
        "- **Without duplicates**: **`Keys must be unique`**, but values can be duplicated.\n",
        "\n",
        "\n",
        "Before Python 3.7, dictionaries were **unordered**, meaning that items were not stored in a specific order. However, with the introduction of Python 3.7, dictionaries now maintain their insertion order.\n",
        "\n",
        "[OrderedDict vs dict in Python: The Right Tool for the Job](https://realpython.com/python-ordereddict/)"
      ],
      "metadata": {
        "id": "ZnFRf53fMrBv"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **2. Creating a Dictionary**\n",
        "\n",
        "Dictionaries are created using curly braces {} with key-value pairs separated by commas.\n",
        "\n",
        "The syntax is:\n",
        "\n",
        "``` Python\n",
        "dictionary = {key1: value1, key2: value2, ...}\n",
        "```\n",
        "\n",
        "Example Code:"
      ],
      "metadata": {
        "id": "dBL7QAI2M7wh"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: genrate a List of 5 american cities\n",
        "\n",
        "american_cities: dict = [\"New York\", \"Los Angeles\", \"Chicago\", \"Houston\", \"Phoenix\"]\n",
        "american_cities\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ePycnz-MWHkJ",
        "outputId": "d4b382c5-49cb-4c2c-b051-acf487650f16"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']"
            ]
          },
          "metadata": {},
          "execution_count": 2
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Create a dictionary to store a person's details\n",
        "person: dict = {\n",
        "    \"name\": \"Alice\",\n",
        "    \"age\": 25,\n",
        "    \"visited_cities\": american_cities\n",
        "}\n",
        "print(person)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "TpI-0iuBNN_b",
        "outputId": "7fa41a7d-aa91-4eb8-940b-ba79a3ead20b"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'name': 'Alice', 'age': 25, 'visited_cities': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "thisdict: dict = dict(name = \"John\", age = 36, country = \"Norway\") # It is also possible to use the dict() constructor to make a dictionary.\n",
        "print(type(thisdict),\" - \", thisdict, )"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "R1hI5O4CVY2b",
        "outputId": "16fb7ad3-861b-4d4d-90a6-b759d761b009"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<class 'dict'>  -  {'name': 'John', 'age': 36, 'country': 'Norway'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **3. Accessing Values**\n",
        "You can access the value associated with a key using square brackets [] or the get() method.\n",
        "\n",
        "\n",
        "Example Code:"
      ],
      "metadata": {
        "id": "ZJQko9uQNQzg"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Access values using keys\n",
        "print(person[\"name\"])  # Output: Alice\n",
        "print(person.get(\"age\", \"99\"))  # Output: 25, if not found it will return 99 (default value)\n",
        "\n",
        "# Access a non-existent key\n",
        "print(person.get(\"country\", \"my_default_vlaue_if_key_not_found\"))  # Output: my_default_vlaue (default value)"
      ],
      "metadata": {
        "id": "h-mvGcmTNVaY",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "069b8b5a-0748-4493-bc1b-d313c07abed7"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Alice\n",
            "25\n",
            "my_default_vlaue_if_key_not_found\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **4. Modifying a Dictionary**\n",
        "\n",
        "\n",
        "You can add new key-value pairs or modify existing ones.\n",
        "\n",
        "Example Code:"
      ],
      "metadata": {
        "id": "k3RdXehaNcNL"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Add a new key-value pair\n",
        "person[\"email\"] = \"alice@example.com\"\n",
        "print(person)\n",
        "\n",
        "# Modify an existing value\n",
        "person[\"age\"] = 26\n",
        "print(person)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lCz289ToNe2a",
        "outputId": "333d3b8d-9838-4e63-96e4-c7123078a445"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'name': 'Alice', 'age': 25, 'city': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 'email': 'alice@example.com'}\n",
            "{'name': 'Alice', 'age': 26, 'city': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix'], 'email': 'alice@example.com'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **5. Deleting Items**\n",
        "\n",
        "\n",
        "You can remove a key-value pair using the del keyword or the pop() method.\n",
        "\n",
        "Note that `pop()` returns the value of the removed key-value pair, whereas `del` does not return anything.\n",
        "\n",
        "You can also use `pop()` with a default value, in case the key is not found in the dictionary:\n",
        "\n",
        "Example Code:"
      ],
      "metadata": {
        "id": "TciSq2w1NirZ"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "person: dict = {'name': 'Alice', 'age': 25, 'email': 'alice@example.com', 'city': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']}\n",
        "print(person)"
      ],
      "metadata": {
        "id": "3rxYNMSkNlnR",
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "outputId": "1f5e31b3-9b80-4c17-fcdf-1696d238ae9f"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'name': 'Alice', 'age': 25, 'email': 'alice@example.com', 'city': ['New York', 'Los Angeles', 'Chicago', 'Houston', 'Phoenix']}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Remove a key-value pair using del\n",
        "del person[\"city\"]\n",
        "print(person)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "SUlED_Lo8PgL",
        "outputId": "90a4029f-1417-4103-840c-8f8dd3e1c8b0"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'name': 'Alice', 'age': 25, 'email': 'alice@example.com'}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "# Remove a key-value pair using pop\n",
        "age: int = person.pop(\"age\", -1)\n",
        "print(\"Removed age:\", age)\n",
        "print(person)\n",
        "\n",
        "print(\"\\n-----\\n\")\n",
        "#Again remove a key which is already removed to check the default value\n",
        "age: int = person.pop(\"age\", -1)\n",
        "print(\"key 'age' not found in dict so returning default value: \", age)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "YmDoNFFy8ZE6",
        "outputId": "1007993a-27bd-44bc-d1c3-0cbea2a73276"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Removed age: 25\n",
            "{'name': 'Alice', 'email': 'alice@example.com'}\n",
            "\n",
            "-----\n",
            "\n",
            "key 'age' not found in dict so returning default value:  -1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **6. Dictionary Methods**\n",
        "\n",
        "Python provides several useful methods for working with dictionaries.\n",
        "\n",
        "\n",
        "| Method   | Description                                                       |   |\n",
        "|----------|-------------------------------------------------------------------|---|\n",
        "| keys()   | Returns a list of all keys in the dictionary.                     |   |\n",
        "| values() | Returns a list of all values in the dictionary.                   |   |\n",
        "| items()  | Returns a list of key-value pairs as tuples.                      |   |\n",
        "| clear()  | Removes all items from the dictionary.                            |   |\n",
        "| update() | Adds or updates multiple key-value pairs from another dictionary. |   |"
      ],
      "metadata": {
        "id": "bEANmh1XORS4"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Get all keys\n",
        "print(\"person.keys()         = \", person.keys()  )  # Output: dict_keys(['name', 'email', 'city', 'age'])\n",
        "\n",
        "# Get all values\n",
        "print(\"person.values()       = \", person.values())  # Output: dict_values(['Alice', 'alice@example.com', 'Los Angeles', 27])\n",
        "\n",
        "# Get all key-value pairs\n",
        "print(\"person.items()        = \", person.items())  # Output: dict_items([('name', 'Alice'), ('email', 'alice@example.com'), ('city', 'Los Angeles'), ('age', 27)])\n",
        "\n",
        "# Update the dictionary\n",
        "person.update({\"city\": \"Los Angeles\", \"age\": 27})\n",
        "print(\"After: person.update  = \", person)\n",
        "\n",
        "# Clear the dictionary\n",
        "person.clear()\n",
        "print(\"After: person.clear() = \", person)  # Output: {}"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UHSHO59jOlHo",
        "outputId": "e7a74636-812c-473e-a37f-4c6a860073a4"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "person.keys()         =  dict_keys(['name', 'email'])\n",
            "person.values()       =  dict_values(['Alice', 'alice@example.com'])\n",
            "person.items()        =  dict_items([('name', 'Alice'), ('email', 'alice@example.com')])\n",
            "After: person.update  =  {'name': 'Alice', 'email': 'alice@example.com', 'city': 'Los Angeles', 'age': 27}\n",
            "After: person.clear() =  {}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **Duplicate Key Not Allowed**\n",
        "\n",
        "\n",
        "Dictionaries cannot have two items with the same key:"
      ],
      "metadata": {
        "id": "QNZjpeX_Uxcj"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "thisdict: dict = {\n",
        "  \"brand\": \"Ford\",\n",
        "  \"model\": \"Mustang\",\n",
        "  \"year\": 1964,\n",
        "  \"year\": 2020 # this will overwrite the previous key:vlaue\n",
        "}\n",
        "print(thisdict)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PIMiMst5U3k6",
        "outputId": "f6e647d9-8d2e-4768-c98c-c1f8ea3178b1"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'brand': 'Ford', 'model': 'Mustang', 'year': 2020}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **7. Iterating Over a Dictionary**\n",
        "\n",
        "You can loop through a dictionary using for loops.\n",
        "\n",
        "Example Code:"
      ],
      "metadata": {
        "id": "fovRmuU-RDJu"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "for key in thisdict:\n",
        "    print(key)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jf99lwnaQbun",
        "outputId": "20859aec-26fa-46f2-86aa-85fac7c9056f"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "brand\n",
            "model\n",
            "year\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "for key, value in thisdict.items():\n",
        "    print(key,\" : \", value)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_q3TV_12QnDm",
        "outputId": "40b4d4f7-ed59-4b7b-8c8d-c73c6459ba60"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "brand  :  Ford\n",
            "model  :  Mustang\n",
            "year  :  2020\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **8. Practical Examples**\n",
        "\n",
        "Here are two practical examples to solidify these concepts.\n",
        "\n",
        "Example 1: Building a Phonebook"
      ],
      "metadata": {
        "id": "XkHE6H4vRWy1"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Create a phonebook\n",
        "phonebook: dict = {\n",
        "    \"Alice\": \"123-456-7890\",\n",
        "    \"Bob\": \"987-654-3210\",\n",
        "    \"Charlie\": \"555-555-5555\"\n",
        "}\n",
        "\n",
        "# Add a new contact\n",
        "phonebook[\"David\"] = \"111-222-3333\"\n",
        "\n",
        "# Search for a contact\n",
        "name: str = input(\"Enter a name to search: \")\n",
        "if name in phonebook:\n",
        "    print(f\"{name}'s phone number is {phonebook[name]}.\")\n",
        "else:\n",
        "    print(f\"{name} is not in the phonebook.\")"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "w5oXu3OVRa4F",
        "outputId": "6829577b-b534-49a1-cce1-e534804c9aa5"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Enter a name to search: Bob\n",
            "Bob's phone number is 987-654-3210.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Example 2: Counting Word Frequencies in a Text"
      ],
      "metadata": {
        "id": "InyXjLrzRsR2"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "sentence = \"\"\"\n",
        "**Projected Economy Size of AI:**\n",
        "\n",
        "The projected economy size of AI is significant, with estimates varying depending on the source and methodology. Here are some notable projections:\n",
        "\n",
        "1. **Global AI Market Size:**\n",
        "\t* By 2025: $190 billion (Source: MarketsandMarkets)\n",
        "\t* By 2030: $1.5 trillion (Source: PwC)\n",
        "2. **AI-Driven Economic Growth:**\n",
        "\t* By 2025: AI is expected to contribute 10% to global GDP growth (Source: Accenture)\n",
        "\t* By 2030: AI is expected to contribute 14% to global GDP growth (Source: PwC)\n",
        "3. **AI-Generated Revenue:**\n",
        "\t* By 2025: AI is expected to generate $15.7 trillion in revenue (Source: IDC)\n",
        "\t* By 2030: AI is expected to generate $33.5 trillion in revenue (Source: McKinsey)\n",
        "4. **Job Market Impact:**\n",
        "\t* By 2025: AI is expected to create 133 million new jobs globally (Source: World Economic Forum)\n",
        "\t* By 2030: AI is expected to automate 30% of current jobs globally (Source: McKinsey)\n",
        "\n",
        "**Industry-Specific Projections:**\n",
        "\n",
        "1. **Healthcare:**\n",
        "\t* By 2025: AI is expected to generate $150 billion in revenue (Source: MarketsandMarkets)\n",
        "2. **Financial Services:**\n",
        "\t* By 2025: AI is expected to generate $100 billion in revenue (Source: Accenture)\n",
        "3. **Manufacturing:**\n",
        "\t* By 2025: AI is expected to generate $50 billion in revenue (Source: IDC)\n",
        "4. **Transportation:**\n",
        "\t* By 2025: AI is expected to generate $20 billion in revenue (Source: MarketsandMarkets)\n",
        "\n",
        "**Regional Projections:**\n",
        "\n",
        "1. **North America:**\n",
        "\t* By 2025: AI is expected to generate $100 billion in revenue (Source: MarketsandMarkets)\n",
        "2. **Europe:**\n",
        "\t* By 2025: AI is expected to generate $50 billion in revenue (Source: IDC)\n",
        "3. **Asia-Pacific:**\n",
        "\t* By 2025: AI is expected to generate $200 billion in revenue (Source: MarketsandMarkets)\n",
        "\n",
        "Note: These projections are based on various assumptions, including the pace of AI development, adoption rates, and economic trends. The actual economy size of AI may vary depending on several factors.\n",
        "\n",
        "\"\"\""
      ],
      "metadata": {
        "id": "BsVpriVbSep9"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Count the frequency of words in a sentence\n",
        "\n",
        "words: list = sentence.split()\n",
        "word_count = {}\n",
        "\n",
        "for word in words:\n",
        "    if word in word_count:\n",
        "        word_count[word] += 1\n",
        "    else:\n",
        "        word_count[word] = 1\n",
        "\n",
        "print(word_count)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "YBQZ6_7cRt6F",
        "outputId": "a4fa2627-15f1-48dd-8a79-6f8e1523ae53"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'**Projected': 1, 'Economy': 1, 'Size': 1, 'of': 5, 'AI:**': 1, 'The': 2, 'projected': 1, 'economy': 2, 'size': 2, 'AI': 17, 'is': 14, 'significant,': 1, 'with': 1, 'estimates': 1, 'varying': 1, 'depending': 2, 'on': 3, 'the': 2, 'source': 1, 'and': 2, 'methodology.': 1, 'Here': 1, 'are': 2, 'some': 1, 'notable': 1, 'projections:': 1, '1.': 3, '**Global': 1, 'Market': 2, 'Size:**': 1, '*': 15, 'By': 15, '2025:': 11, '$190': 1, 'billion': 8, '(Source:': 15, 'MarketsandMarkets)': 5, '2030:': 4, '$1.5': 1, 'trillion': 3, 'PwC)': 2, '2.': 3, '**AI-Driven': 1, 'Economic': 2, 'Growth:**': 1, 'expected': 13, 'to': 15, 'contribute': 2, '10%': 1, 'global': 2, 'GDP': 2, 'growth': 2, 'Accenture)': 2, '14%': 1, '3.': 3, '**AI-Generated': 1, 'Revenue:**': 1, 'generate': 9, '$15.7': 1, 'in': 9, 'revenue': 9, 'IDC)': 3, '$33.5': 1, 'McKinsey)': 2, '4.': 2, '**Job': 1, 'Impact:**': 1, 'create': 1, '133': 1, 'million': 1, 'new': 1, 'jobs': 2, 'globally': 2, 'World': 1, 'Forum)': 1, 'automate': 1, '30%': 1, 'current': 1, '**Industry-Specific': 1, 'Projections:**': 2, '**Healthcare:**': 1, '$150': 1, '**Financial': 1, 'Services:**': 1, '$100': 2, '**Manufacturing:**': 1, '$50': 2, '**Transportation:**': 1, '$20': 1, '**Regional': 1, '**North': 1, 'America:**': 1, '**Europe:**': 1, '**Asia-Pacific:**': 1, '$200': 1, 'Note:': 1, 'These': 1, 'projections': 1, 'based': 1, 'various': 1, 'assumptions,': 1, 'including': 1, 'pace': 1, 'development,': 1, 'adoption': 1, 'rates,': 1, 'economic': 1, 'trends.': 1, 'actual': 1, 'may': 1, 'vary': 1, 'several': 1, 'factors.': 1}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "AI generated code:"
      ],
      "metadata": {
        "id": "gfcZkP6lTiPs"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: sort the word count variable according to its value in descending order\n",
        "\n",
        "# Sort the word_count dictionary by value in descending order\n",
        "sorted_word_count = dict(sorted(word_count.items(), key=lambda item: item[1], reverse=True))\n",
        "\n",
        "sorted_word_count\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "eR0TmgL1S0sU",
        "outputId": "efb81490-bac4-4816-92ce-920c44e1d902"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "execute_result",
          "data": {
            "text/plain": [
              "{'AI': 17,\n",
              " '*': 15,\n",
              " 'By': 15,\n",
              " '(Source:': 15,\n",
              " 'to': 15,\n",
              " 'is': 14,\n",
              " 'expected': 13,\n",
              " '2025:': 11,\n",
              " 'generate': 9,\n",
              " 'in': 9,\n",
              " 'revenue': 9,\n",
              " 'billion': 8,\n",
              " 'of': 5,\n",
              " 'MarketsandMarkets)': 5,\n",
              " '2030:': 4,\n",
              " 'on': 3,\n",
              " '1.': 3,\n",
              " 'trillion': 3,\n",
              " '2.': 3,\n",
              " '3.': 3,\n",
              " 'IDC)': 3,\n",
              " 'The': 2,\n",
              " 'economy': 2,\n",
              " 'size': 2,\n",
              " 'depending': 2,\n",
              " 'the': 2,\n",
              " 'and': 2,\n",
              " 'are': 2,\n",
              " 'Market': 2,\n",
              " 'PwC)': 2,\n",
              " 'Economic': 2,\n",
              " 'contribute': 2,\n",
              " 'global': 2,\n",
              " 'GDP': 2,\n",
              " 'growth': 2,\n",
              " 'Accenture)': 2,\n",
              " 'McKinsey)': 2,\n",
              " '4.': 2,\n",
              " 'jobs': 2,\n",
              " 'globally': 2,\n",
              " 'Projections:**': 2,\n",
              " '$100': 2,\n",
              " '$50': 2,\n",
              " '**Projected': 1,\n",
              " 'Economy': 1,\n",
              " 'Size': 1,\n",
              " 'AI:**': 1,\n",
              " 'projected': 1,\n",
              " 'significant,': 1,\n",
              " 'with': 1,\n",
              " 'estimates': 1,\n",
              " 'varying': 1,\n",
              " 'source': 1,\n",
              " 'methodology.': 1,\n",
              " 'Here': 1,\n",
              " 'some': 1,\n",
              " 'notable': 1,\n",
              " 'projections:': 1,\n",
              " '**Global': 1,\n",
              " 'Size:**': 1,\n",
              " '$190': 1,\n",
              " '$1.5': 1,\n",
              " '**AI-Driven': 1,\n",
              " 'Growth:**': 1,\n",
              " '10%': 1,\n",
              " '14%': 1,\n",
              " '**AI-Generated': 1,\n",
              " 'Revenue:**': 1,\n",
              " '$15.7': 1,\n",
              " '$33.5': 1,\n",
              " '**Job': 1,\n",
              " 'Impact:**': 1,\n",
              " 'create': 1,\n",
              " '133': 1,\n",
              " 'million': 1,\n",
              " 'new': 1,\n",
              " 'World': 1,\n",
              " 'Forum)': 1,\n",
              " 'automate': 1,\n",
              " '30%': 1,\n",
              " 'current': 1,\n",
              " '**Industry-Specific': 1,\n",
              " '**Healthcare:**': 1,\n",
              " '$150': 1,\n",
              " '**Financial': 1,\n",
              " 'Services:**': 1,\n",
              " '**Manufacturing:**': 1,\n",
              " '**Transportation:**': 1,\n",
              " '$20': 1,\n",
              " '**Regional': 1,\n",
              " '**North': 1,\n",
              " 'America:**': 1,\n",
              " '**Europe:**': 1,\n",
              " '**Asia-Pacific:**': 1,\n",
              " '$200': 1,\n",
              " 'Note:': 1,\n",
              " 'These': 1,\n",
              " 'projections': 1,\n",
              " 'based': 1,\n",
              " 'various': 1,\n",
              " 'assumptions,': 1,\n",
              " 'including': 1,\n",
              " 'pace': 1,\n",
              " 'development,': 1,\n",
              " 'adoption': 1,\n",
              " 'rates,': 1,\n",
              " 'economic': 1,\n",
              " 'trends.': 1,\n",
              " 'actual': 1,\n",
              " 'may': 1,\n",
              " 'vary': 1,\n",
              " 'several': 1,\n",
              " 'factors.': 1}"
            ]
          },
          "metadata": {},
          "execution_count": 26
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## **9. Common Pitfalls**\n",
        "\n",
        "* Using a non-existent key without checking first for e.g. \"\n",
        "``` python\n",
        "print(my_dict.get(\"name_1\")) # Output: None\n",
        "print(my_dict.get(\"name_1\", \"No name found\")) # Output: No name found\n",
        "print(my_dict[\"name_1\"])  # (raises a KeyError).\n",
        "```\n",
        "\n",
        "* Always use get() or check if the key exists with in to avoid error.\n",
        "* Forgetting that dictionary keys must be immutable (e.g., strings, numbers, or tuples).\n",
        "* Assuming dictionaries are ordered (in Python 3.6+, they retain insertion order, but this is not guaranteed in older versions)."
      ],
      "metadata": {
        "id": "-2Tiy0URT5B7"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# prompt: generate a working example of all dictionary function\n",
        "\n",
        "# Example Dictionary\n",
        "my_dict = {\n",
        "  \"name\": \"John\",\n",
        "  \"age\": 30,\n",
        "  \"city\": \"New York\"\n",
        "}\n",
        "\n",
        "# 1. Accessing Items\n",
        "print(\"1. Accessing Items\")\n",
        "print(\"Name:\", my_dict[\"name\"])  # Accessing by key\n",
        "print(\"Age:\", my_dict.get(\"age\"))  # Accessing using get()\n",
        "print(\"City (using get):\", my_dict.get(\"city\"))\n",
        "\n",
        "# 2. Adding Items\n",
        "print(\"\\n2. Adding Items\")\n",
        "my_dict[\"email\"] = \"john@example.com\"\n",
        "print(\"Dictionary after adding email:\", my_dict)\n",
        "\n",
        "# 3. Modifying Items\n",
        "print(\"\\n3. Modifying Items\")\n",
        "my_dict[\"age\"] = 31\n",
        "print(\"Dictionary after modifying age:\", my_dict)\n",
        "\n",
        "# 4. Removing Items\n",
        "print(\"\\n4. Removing Items\")\n",
        "my_dict.pop(\"city\")\n",
        "print(\"Dictionary after removing city (using pop):\", my_dict)\n",
        "del my_dict[\"email\"]\n",
        "print(\"Dictionary after removing email (using del):\", my_dict)\n",
        "\n",
        "# 5. Dictionary Methods\n",
        "print(\"\\n5. Dictionary Methods\")\n",
        "print(\"Keys:\", my_dict.keys())\n",
        "print(\"Values:\", my_dict.values())\n",
        "print(\"Items:\", my_dict.items())\n",
        "\n",
        "# 6. Clearing the Dictionary\n",
        "print(\"\\n6. Clearing the Dictionary\")\n",
        "my_dict.clear()\n",
        "print(\"Dictionary after clearing:\", my_dict)\n",
        "\n",
        "# Adding items back for further examples\n",
        "my_dict = {\n",
        "  \"name\": \"John\",\n",
        "  \"age\": 30,\n",
        "  \"city\": \"New York\"\n",
        "}\n",
        "\n",
        "# 7. Updating the Dictionary\n",
        "print(\"\\n7. Updating the Dictionary\")\n",
        "my_dict.update({\"age\": 32, \"country\": \"USA\"})\n",
        "print(\"Dictionary after updating:\", my_dict)\n",
        "\n",
        "# 8. Iterating Through a Dictionary\n",
        "print(\"\\n8. Iterating Through a Dictionary\")\n",
        "print(\"Iterating through keys:\")\n",
        "for key in my_dict:\n",
        "  print(key)\n",
        "\n",
        "print(\"\\nIterating through values:\")\n",
        "for value in my_dict.values():\n",
        "  print(value)\n",
        "\n",
        "print(\"\\nIterating through items (key-value pairs):\")\n",
        "for key, value in my_dict.items():\n",
        "  print(f\"{key}: {value}\")\n",
        "\n",
        "#9 checking if a key exist\n",
        "print(\"\\n9. checking if a key exist\")\n",
        "if \"name\" in my_dict:\n",
        "    print(\"Name exist\")\n",
        "else:\n",
        "    print(\"Name do not exist\")\n",
        "\n",
        "# 10. Dictionary Length\n",
        "print(\"\\n10. Dictionary Length\")\n",
        "print(\"Length of the dictionary:\", len(my_dict))\n",
        "\n",
        "# 11. Creating a dictionary from iterable\n",
        "print(\"\\n11. Creating a dictionary from iterable\")\n",
        "iterable = [(\"key1\", \"value1\"), (\"key2\", \"value2\"), (\"key3\", \"value3\")]\n",
        "new_dict = dict(iterable)\n",
        "print(\"new dictionary:\", new_dict)\n",
        "\n",
        "# 12. Copying a dictionary\n",
        "print(\"\\n12. Copying a dictionary\")\n",
        "copied_dict = my_dict.copy()\n",
        "print(\"Copied dictionary:\", copied_dict)\n",
        "\n",
        "# 13. Nested Dictionaries\n",
        "print(\"\\n13. Nested Dictionaries\")\n",
        "nested_dict = {\n",
        "    \"person1\": {\"name\": \"Alice\", \"age\": 25},\n",
        "    \"person2\": {\"name\": \"Bob\", \"age\": 30}\n",
        "}\n",
        "print(\"Nested dictionary:\", nested_dict)\n",
        "print(\"Alice's age:\", nested_dict[\"person1\"][\"age\"])\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "XjTwM33kXW7J",
        "outputId": "926d332a-4253-4a99-f3b3-b6e9599b2bc6"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1. Accessing Items\n",
            "Name: John\n",
            "Age: 30\n",
            "City (using get): New York\n",
            "\n",
            "2. Adding Items\n",
            "Dictionary after adding email: {'name': 'John', 'age': 30, 'city': 'New York', 'email': 'john@example.com'}\n",
            "\n",
            "3. Modifying Items\n",
            "Dictionary after modifying age: {'name': 'John', 'age': 31, 'city': 'New York', 'email': 'john@example.com'}\n",
            "\n",
            "4. Removing Items\n",
            "Dictionary after removing city (using pop): {'name': 'John', 'age': 31, 'email': 'john@example.com'}\n",
            "Dictionary after removing email (using del): {'name': 'John', 'age': 31}\n",
            "\n",
            "5. Dictionary Methods\n",
            "Keys: dict_keys(['name', 'age'])\n",
            "Values: dict_values(['John', 31])\n",
            "Items: dict_items([('name', 'John'), ('age', 31)])\n",
            "\n",
            "6. Clearing the Dictionary\n",
            "Dictionary after clearing: {}\n",
            "\n",
            "7. Updating the Dictionary\n",
            "Dictionary after updating: {'name': 'John', 'age': 32, 'city': 'New York', 'country': 'USA'}\n",
            "\n",
            "8. Iterating Through a Dictionary\n",
            "Iterating through keys:\n",
            "name\n",
            "age\n",
            "city\n",
            "country\n",
            "\n",
            "Iterating through values:\n",
            "John\n",
            "32\n",
            "New York\n",
            "USA\n",
            "\n",
            "Iterating through items (key-value pairs):\n",
            "name: John\n",
            "age: 32\n",
            "city: New York\n",
            "country: USA\n",
            "\n",
            "9. checking if a key exist\n",
            "Name exist\n",
            "\n",
            "10. Dictionary Length\n",
            "Length of the dictionary: 4\n",
            "\n",
            "11. Creating a dictionary from iterable\n",
            "new dictionary: {'key1': 'value1', 'key2': 'value2', 'key3': 'value3'}\n",
            "\n",
            "12. Copying a dictionary\n",
            "Copied dictionary: {'name': 'John', 'age': 32, 'city': 'New York', 'country': 'USA'}\n",
            "\n",
            "13. Nested Dictionaries\n",
            "Nested dictionary: {'person1': {'name': 'Alice', 'age': 25}, 'person2': {'name': 'Bob', 'age': 30}}\n",
            "Alice's age: 25\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### **Dictionary Comprehensions**\n",
        "\n",
        "Dictionary comprehensions provide a concise way to create dictionaries in Python. They are similar to list comprehensions but used for creating dictionaries instead of lists. Let's explore how dictionary comprehensions work and see some examples.\n",
        "\n",
        "#### **Basic Syntax**\n",
        "\n",
        "The basic syntax of a dictionary comprehension is:\n",
        "\n",
        "```python\n",
        "{key_expression: value_expression for item in iterable if condition}\n",
        "```"
      ],
      "metadata": {
        "id": "REZCeIIblLb9"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "original_dict = {'a': 1, 'b': 2, 'c': 3}\n",
        "print(\"original_dict = \", original_dict)\n",
        "doubled_dict = {k: v*2 for k, v in original_dict.items()}\n",
        "print(\"doubled_dict  = \", doubled_dict)  # Output: {'a': 2, 'b': 4, 'c': 6}"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "R7j8Pmn1leMe",
        "outputId": "f694dcb5-9629-4dbe-e975-023ceca5a00d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "original_dict =  {'a': 1, 'b': 2, 'c': 3}\n",
            "doubled_dict  =  {'a': 2, 'b': 4, 'c': 6}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### **Practice Exercise**\n",
        "\n",
        "Try to create a dictionary comprehension that converts a list of temperatures in Celsius to Fahrenheit. The formula to convert Celsius to Fahrenheit is `F = (C * 9/5) + 32`."
      ],
      "metadata": {
        "id": "YGFdoRBPmSST"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "celsius_temps = [0, 10, 20, 30, 40]\n",
        "fahrenheit_temps = {str(c)+\"c\":  str((c * 9/5) + 32)+\"f\" for c in celsius_temps}\n",
        "print(fahrenheit_temps)  # Output: {0: 32, 10: 50, 20: 68, 30: 86, 40: 104}"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "14tudzTql_rM",
        "outputId": "430dbe05-1344-42ef-fdb6-f091d3553399"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{'0c': '32.0f', '10c': '50.0f', '20c': '68.0f', '30c': '86.0f', '40c': '104.0f'}\n"
          ]
        }
      ]
    }
  ]
}